use crate::entity::cms_article;
use crate::entity::cms_article_category;
use crate::entity::cms_category;
use crate::entity::prelude::*;

use ane_macros::model_fetch;
use sea_orm::{
    ColumnTrait, ConnectionTrait, DbConn, DerivePartialModel, EntityTrait, FromQueryResult,
    PaginatorTrait, PartialModelTrait, QueryFilter, QueryOrder, QueryTrait, Related,
};
use serde::Serialize;

use super::CategoryVo;

/// cms的接口
pub struct Cms;

// 文章详细的数据展示
#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "CmsArticle")]
pub struct ArticleVo {
    pub id: i32,
    pub title: String,
    pub author: String,
    pub fromurl: String,
    pub image: String,
    pub keywords: String,
    pub description: String,
    pub allow_comments: bool,
    pub read_number: u32,
    pub content: String,
    pub publish_at: chrono::NaiveDateTime,
}

#[allow(unused)]
impl Cms {
    model_fetch!(
        #model=cms_article
        #filter=[Status.eq(2)]
        /// 根据获取一篇文章
        pub fn fetch_article(Id.eq(id:i32))
    );

    /// 列出文章
    ///
    /// 返回(artiles,total_item,total_page)
    pub async fn list_article<T>(
        db: &DbConn,
        page: u64,
        page_size: u64,
        category_id: Option<i32>,
        key: Option<String>,
    ) -> Result<Option<(Vec<T>, u64, u64)>, sea_orm::DbErr>
    where
        T: PartialModelTrait + Send + Sync,
    {
        let sql = CmsArticle::find()
            .filter(cms_article::Column::Status.eq(2))
            .apply_if(key, |sql, val| {
                sql.filter(cms_article::Column::Title.like(val))
            })
            .apply_if(category_id, |sql, category_id| {
                sql.inner_join(cms_category::Entity)
                    .filter(cms_category::Column::Status.eq(1))
                    .filter(cms_article_category::Column::CategoryId.eq(category_id))
            })
            .order_by_desc(cms_article::Column::Id)
            .into_partial_model()
            .paginate(db, page_size);
        let count = sql.num_items_and_pages().await?;
        let articles = sql.fetch_page(page).await?;
        Ok(Some((
            articles,
            count.number_of_items,
            count.number_of_pages,
        )))
    }

    /// 获得分类
    pub async fn fetch_category(
        db: &DbConn,
        status: Option<i8>,
    ) -> Result<Vec<CategoryVo>, sea_orm::DbErr> {
        let mut childrens: Vec<(cms_category::Model, Vec<CategoryVo>)> = vec![];
        let mut iter = cms_category::Entity::find()
            .apply_if(status, |sql, value| {
                sql.filter(cms_category::Column::Status.eq(value))
            })
            .order_by_asc(cms_category::Column::Lt)
            .all(db)
            .await?
            .into_iter();
        let (result, _) = build_tree(None, &mut iter);
        return Ok(result);
    }
}

fn build_tree<T>(
    r_boundary: Option<i32>,
    iter: &mut T,
) -> (Vec<CategoryVo>, Option<cms_category::Model>)
where
    T: Iterator<Item = cms_category::Model>,
{
    let mut children = vec![];
    let mut i = 1;
    let mut node = None;
    loop {
        if node.is_none() {
            node = iter.next();
        }
        if let Some(n) = node {
            if matches!(r_boundary,Some(x)if x<=n.rt) {
                return (children, Some(n));
            }
            let (c, next_node) = build_tree(Some(n.rt), iter);
            children.push(CategoryVo {
                id: n.id,
                p_id: n.p_id,
                sort: i,
                name: n.name,
                alias: n.alias,
                icon: n.icon,
                children: c,
            });
            i += 1;
            node = next_node;
        } else {
            break;
        }
    }
    return (children, None);
}
